/*
 * File:       eg_map.h
 * Created on: Sept 3
 * Purpose:    Contains functions for loading and validating maps from .egm files
 */

/*
 Copyright 2009 James Youngquist, Colin Scott.

 This file is part of ElectroGladiator.  ElectroGladiator is free
 software: you can redistribute it and/or modify it under the terms
 of the GNU General Public License as published by  the Free
 Software Foundation, either version 3 of the License, or (at your
 option) any later version.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>
#include <stdio.h>
#include <math.h>

#include "eg_geom.h"
#include "eg_map.h"
#include "eg_data.h"

#define NUM_PLAYERS 1   /* To be removed when we have a server */


// Private Function
int boundary_line (Map *map, Line *l);

// Reads in map from text file
void readin_map(char *filename, Map *map) {
    FILE *f = fopen(filename, "r");

    if (!f) {
        fprintf(stderr, "Failed to open map data file.\n");
        exit(1);
    }

    // Width
    fscanf(f, "%lf", &(map->width));

    // Height
    fscanf(f, "%lf", &(map->height));

    // # Lines
    // Excludes implicit lines so read-in amount needs to be increased by 4
    fscanf(f, "%d\n", &(map->num_lines));
    map->num_lines += 4;

    // Allocate room for the lines
    // !! This needs to be freed at some point...
    map->lines = calloc(map->num_lines, sizeof(Line*));

    // Create the implicit walls
    map->lines[0] = new_line(0, 0, map->width, 0); /* bottom */
    map->lines[1] = new_line(map->width, 0, map->width, map->height); /* right  */
    map->lines[2] = new_line(0, map->height, map->width, map->height); /* top    */
    map->lines[3] = new_line(0, 0, 0, map->height); /* left   */

    // The rest of the data is variable length, so use switch statements until EOF.
    // Index starts at 4 because the walls are implicit in the map data and so have
    // already been added above.
    int line_index = 4;
    while (line_index < map->num_lines) {
        // given that the data is in a known format, 80 byte buffer s/b perfectly
        // adequate
        char buf[80] = { '\0' };

        fgets(buf, sizeof(buf), f);

        // I was going to do a switch statement here, but then I got frustated with
        // the compiler errors I was getting, so I gave up.
        if (buf[0] == 'l') {
            double endpoints[4];
            // Format is "l,end1,end2,end3,end4"
            char delim[] = ",";
            char *result = NULL;
            // throw away 'l'
            result = strtok(buf, delim);
            // read in the remaining tokens
            int i;
            for (i = 0; i < 4; i++) {
                result = strtok(NULL, delim);
                endpoints[i] = atof(result);
            }

            // an interior wall
            map->lines[line_index] = new_line(endpoints[0], endpoints[1],
                    endpoints[2], endpoints[3]);
            line_index++;
        }
    }
    fclose(f);

    // This is just for now. Figure out how to get info from server later.
    map->num_players = NUM_PLAYERS;
    map->players = calloc(map->num_players, sizeof(Player *));

    int i;
    for (i = 0; i < map->num_players; i++) {
        map->players[i] = new_player(70, 40, M_PI);
    }

		// Initialize rock linked list
		ll_init(&map->rocks, ROCK);
}

/* Returns 1 if the map is valid (contains no intersecting lines).
 * Else, returns 0
 * Todo: move this into its own module, and have the function take
 * a Map paramater
 */  
int validate_map (Map *map) {
	int i;

	// Iterate through each line stored in the map struct
	for (i = 0; i < map->num_lines; i++) {
		int j;	
		// Iterate through all other lines looking for intersections
		// This will run in roughly O(N log(N)) 		
		for (j = i + 1; j < map->num_lines; j++) {
			// eg_vision#find_intersections() requires a Point* as a param
			// It is somewhat inefficient to allocate a point just to have
			// it be freed, but whatever. Maybe I'll need that point for
			// map auto-correction.
			Point *p = calloc(1, sizeof(Point));
		
			// If *crossing* intersection found, return 0
			// It's o.k. if the intersection is created by an endpoint.
			// I would factor out the free(p) statement, but the
			// fact that return statements exit is a problem.
			if((intersection(map->lines[i], map->lines[j], p)) && 
					!((is_endpoint(p, map->lines[i])) || 
					(is_endpoint(p, map->lines[j])))) {
				fprintf(stderr, "Crossing intersection found at (%lf,%lf)\n", p->x, p->y);
	
				// Check for lines that go outside the boundaries of the map.
				if( boundary_line(map, map->lines[i]) ) {
					fprintf(stderr, "The following line goes outside the map boundaries:");
					// Hmmm, print_line sends output to stdout, not sterr. Meh.
					print_line(map->lines[j]);
					printf("\n");	
				} else if ( boundary_line(map, map->lines[j]) ) {
					fprintf(stderr, "The following line goes outside the map boundaries:");
					print_line(map->lines[i]);
					printf("\n");			
				}
	
				free(p);
				return 1;
			} else {
				free(p);
			}
		}
	}
	
	// map has passed the check
	return 0;
}

// Returns whether the line is a boundary line
// Pre: boundary lines hug the corners of the map exactly
// Private Function
int boundary_line (Map *map, Line *l) {
	// If both l->p1 and l->p2 lie on corners, return 1
	if ( ( ( l->p1.x == map->width || l->p1.x == 0.0) && 
			( l->p1.y == map->height || l->p1.y == 0.0) ) &&
			( (l->p2.x == map->width || l->p2.x == 0.0) && 
			(l->p2.y == map->height || l->p2.y == 0.0) ) ) { 
		return 1;
	} else {
		return 0;
	}
}
